/* biogeo.h is part of VIP program
 * Written by J. Salvador Arias, 2010
 *      CONICET, INSUE, Instituto Miguel Lillo,
 *      Miguel Lillo 205, S.M. de Tucuman (4000)
 *      Tucuman, Argentina
 *      e-mail: jsalarias@csnat.unt.edu.ar
 *
 * VIP is a free software; you can redistribute it and/or
 * modify it under the terms of the GNU General Public
 * License as published by the Free Software Foundation and
 * Creative Commons.
 *
 * This file and the VIP program is distributed in the hope
 * that it will be useful, but WITHOUT ANY WARRANTY; without
 * even the implied warranty of MERCHANTABILITY or FITNESS
 * FOR A PARTICULAR PURPOSE.
 * See the GNU General Public License for more details.
 *
 * To view a copy of this license, visit
 * http://creativecommons.org/licenses/GPL/2.0/
 * or send a letter to
 * Creative Commons, 171 Second Street, Suite 300,
 * San Francisco, California, 94105, USA.
 */

#ifndef BIOGEOGRAPHY_HEADER_INCLUDED
#define BIOGEOGRAPHY_HEADER_INCLUDED

/* ------ Data types for biogeographic data ------ */

#include "ghead.h"
#include "bitfield.h"
#include "progbar.h"

/* Tree data */
typedef struct tagPHYLOTREE PHYLOTREE;
typedef struct tagPHYLONODE PHYLONODE;

/* Terminal data */
typedef struct tagTERMINAL TERMINAL;

/* Georeferenced data */
typedef struct tagGEOREF GEOREF;

/* Reconstructions */
typedef struct tagRECONS RECONS;

/* Allopatry sets */
typedef struct tagALLOPATRY ALLOPATRY;

/* Search Parameters */
typedef struct tagSEARCHPARAM SEARCHPARAM;

/* Global variables */

#define NO_AGE  50000

/* Tree list */
GList* trees;
GList* lastTree;
SCOUNTER numTrees;

#define GETTREES       trees
#define SETTREES(x)    trees = (x)
#define GETLASTTREE    lastTree
#define SETLASTTREE(x) lastTree = (x)

#define GETNUMTREES         numTrees
#define SETNUMTREES(x)      numTrees = (x)
#define INCREASENUMTREES(x) numTrees += (x)
#define DECREASENUMTREES(x) numTrees -= (x)

/* Intialization, Creation, and destruction */
void StartBioGeo ();
void DestroyBioGeo ();
void DestroyTree (PHYLOTREE* tree);

PHYLOTREE* CreateTree (gchar* name, SCOUNTER id);
GNode* CreateNode (PHYLOTREE* tree, GNode* anc, GNode* lastSibling, SCOUNTER id);
void PrepareTree (PHYLOTREE* tree);
PHYLOTREE* GetTreeFromID (SCOUNTER id);

#define TREE_TERMS_UP   1
#define TREE_TERMS_DOWN 2
#define TREE_TERMS_MIX  3
#define TREE_TERMS_DEF  4
void SortNodes (SFLAG mode);

SFLAG SetNodeAge (GNode* node, SCOUNTER age, SFLAG changeAll);
PHYLONODE* GetNodeFromID (PHYLOTREE* tree, SCOUNTER id);
void PutFillValue (PHYLONODE* node, SCOUNTER fillValue);

/* Terminal list */
GList* spp;
GList* lastSpp;
SCOUNTER numSpp;

#define GETSPP        spp
#define SETSPP(x)     spp = (x)
#define GETLASTSPP    lastSpp
#define SETLASTSPP(x) lastSpp = (x)

#define GETNUMSPP         numSpp
#define SETNUMSPP(x)      numSpp = (x)
#define INCREASENUMSPP(x) numSpp += (x)
#define DECREASENUMSPP(x) numSpp -= (x)

TERMINAL* CreateTerminal (GNode* node);
void DestroyTermList (GList* list);

TERMINAL* GetTermFromName (gchar* name);
gchar* AddSynonim (TERMINAL* actTerm, gchar* syn);

/* Georeference list */
GList* geoRefs;
GList* lastGeoRef;
SCOUNTER numGeoRefs;

#define GETGEOREF        geoRefs
#define SETGEOREF(x)     geoRefs = (x)
#define GETLASTGEOREF    lastGeoRef
#define SETLASTGEOREF(x) lastGeoRef = (x)

#define GETNUMGEOREFS         numGeoRefs
#define SETNUMGEOREFS(x)      numGeoRefs = (x)
#define INCREASENUMGEOREFS(x) numGeoRefs += (x)
#define DECREASENUMGEOREFS(x) numGeoRefs -= (x)

GList* CreateGeoRef (GList* last, GList* term, SREAL lon, SREAL lat);
GEOREF* AddGeoRef (SREAL lon, SREAL lat, GNode* node);
void DeleteGeoRef (GEOREF* toDel);
void DestroyGeoList (GList* toDel);

void UpdateLimits (GEOREF* geo);

SCOUNTER GetNumTermsWithGeo ();
void UpdateWithData (TERMINAL* actTerm);

/* Reconstructions */
RECONS* CreateRecons (PHYLONODE* node);
void DestroySingleRec (GPtrArray* recArray);
void DestroyRecList (GList* recList);
void DestroyRecs ();

void SetTreeBestScore (PHYLOTREE* tree);
SREAL GetBestScore (GList* recs);
void FilterRecs (SREAL extra);
SCOUNTER FilterRecList (GList** recs, SREAL bound, SREAL extra);
GList* CopyActRec (PHYLOTREE* tree);

/* Allopatry sets */
void RemoveAlloSets ();
void DestroyAlloSet (ALLOPATRY* alloSet);

/* General */
SREAL worldStart;

SREAL maxAzimuth;
SREAL minAzimuth;
SREAL maxInclination;
SREAL minInclination;

#define GETMAXAZM    maxAzimuth
#define GETMINAZM    minAzimuth
#define GETMAXINC    maxInclination
#define GETMININC    minInclination
#define SETMAXAZM(x) maxAzimuth = (x)
#define SETMINAZM(x) minAzimuth = (x)
#define SETMAXINC(x) maxInclination = (x)
#define SETMININC(x) minInclination = (x)

#define FROMLATTOINC(x) 90.00000000 - (x)
#define FROMINCTOLAT(x) 90.00000000 - (x)
#define FROMLONTOAZM(x) ((x) > worldStart) ? (x) - worldStart : (x) + 360.00000000 - worldStart
#define FROMAZMTOLON(x) (((x) + worldStart) < 180.00000001) ? (x) + worldStart : (x) - 360.00000000 + worldStart

SEARCHPARAM params;
#define USE_INTS  0
#define OVER_REAL 1
#define USE_TIME  2
#define TIME_REAL 4

#define NORMAL_SEARCH 0
#define USE_LATEOVER  1
#define CONSTR_SEARCH 2

#define VIC_NODE   1
#define REMOV_NODE 2
#define TIME_LAG   4

#define PAGE_SEARCH   0x0001
#define FAST_SEARCH   0x0002
#define FIRST_SECTOR  0x0004
#define FULL_SECTOR   0x0008
#define USE_SECTORS   0x000C
#define BLIND_ANNEAL  0x0010
#define GIBBS_ANNEAL  0x0020
#define FLIP_NODES    0x0040
#define NIXON_ANNEAL  0x0080
#define REC_FUSING    0x0100

/* ------ Searching functions ------ */

void SetRec (GPtrArray* recArray);
void MakeOptimization (SFLAG justCount);
void SearchMain (PROGRESSSTRUCT* progress);
void RefineRecs (PROGRESSSTRUCT* progress);

SFLAG ChangeNode (GNode* node);
void SetNodeAsRemoved (GNode* node);
void SetNodeAsPartialRemov (GNode* node);

void SetConstrains (SFLAG toCons);

void MakeConsensus ();
void MakeCommonBarriers ();


/* ------ Type definitions ------ */

struct tagPHYLOTREE {
 gchar* name;
 SCOUNTER id;
 GNode* root;
 GList* list;
 GPtrArray* nodeArray;      /*GNode pointers */
 GPtrArray* recOR;
 GPtrArray* recCons;
 GList* recs;
 GList* actRec;
 SCOUNTER stored;
 SCOUNTER suppNodes;
 //Graphic part
 SCOUNTER maxTreeAge;
 SCOUNTER x;
 SCOUNTER y;
 SREAL best;
 SREAL worst;
};

struct tagPHYLONODE {
 gchar* name;
 GNode* node;
 TERMINAL* term;
 PHYLOTREE* tree;
 SCOUNTER minAge;
 SCOUNTER id;           /* Simple id, used for reconstructions */
 RECONS* rec;           /* Actual reconstruction */
 SREAL bremer;          /* "Bremer" support for the node */
 ALLOPATRY* alloSet;    /* Nodes with the same allopatric pattern */
 SCOUNTER withData;
 SCOUNTER fill;
 SFLAG constrained;
 /* Graphic part */
 SCOUNTER numTerms;
 SINTEGER size;
 SCOUNTER level;
 SCOUNTER nested;
 /* Graphic part, virtual screen */
 SINTEGER ageX;
 SINTEGER minX;
 SINTEGER maxX;
 SINTEGER y;
 SINTEGER startY;
 SINTEGER endY;
 /* Graphic part, actual screen */
 SINTEGER actX;
 SINTEGER actY;
 SINTEGER topY;
 SINTEGER downY;
 gpointer layout;
};

struct tagTERMINAL {
 gchar* name;
 GNode* node;
 GList* list;
 GList* firstGeo;
 GList* synonyms;
 SCOUNTER numGeo;
 BITFIELD* obs;
};

struct tagGEOREF {
 gchar* name;
 SREAL lat;
 SREAL lon;
 GList* list;
 SCOUNTER actCell;
 /* Standarized georeference */
 SREAL inclination;     /* Zenith from equatorial plane to north pole */
 SREAL azimuth;         /* Reference plane, the equatorial plane */
 GList* sp;
 /* Graphic part, actual screen */
 SINTEGER actX;
 SINTEGER actY;
 /* Other info */
 gchar* collec;         /* Collection name */
 gchar* collector;
 gchar* catalog;        /* Catalog id */
 gchar* url;            /* Internet url */
 gchar* reference;      /* Bibliographic reference */
 gchar* identifier;     /* The person that made the identification */
 gchar* sampleDate;     /* Sampling date */
};

struct tagRECONS {
 PHYLONODE* node;
 BITFIELD* cells;       /* Cells asigned to the node */
 BITFIELD* obs;         /* Cells with "physical" points */
 PHYLONODE* setA;
 PHYLONODE* setB;
 PHYLONODE* removSet;
 SFLAG nodeFlag;
 /* Data for incremental optimization */
 SCOUNTER numVics;
 SCOUNTER numRemovNodes;
 SCOUNTER numNoVics;
 SREAL cost;
 /* Data for node cost calculation */
 SCOUNTER numCells;
 SCOUNTER numObs;
 SCOUNTER active;
 SREAL overlap;
 SCOUNTER timeLag;
 SCOUNTER maxAge;
 /* Barrier */
 GList* triangles;
};

struct tagALLOPATRY {
 GList* list;
 BITFIELD* baseA;
 BITFIELD* baseB;
 BITFIELD* setA;
 BITFIELD* setB;
 SCOUNTER numNodes;
 GList* nodeList;
 /* Barrier */
 GList* triangles;
};

struct tagSEARCHPARAM {
 SREAL costNoVic;
 SREAL costRemov;
 SREAL costPartRemov;
 SREAL costTimeLag;
 SREAL overlap;
 SREAL extra;
 SINTEGER timeLag;
 SCOUNTER timeDiff;
 SFLAG mode;
 SFLAG search;
 SCOUNTER hold;
 SCOUNTER maxHold;
 SFLAG algorithm;
 SFLAG keepAll;
 SCOUNTER its;      /* Iterations */
 SCOUNTER sectSize;
 SCOUNTER generations;
 SCOUNTER acceptEqual;
};

#endif
